package com.ztgf.logistics.service.deppon;

import com.alibaba.fastjson.JSON;
import com.baomidou.mybatisplus.mapper.EntityWrapper;
import com.baomidou.mybatisplus.mapper.Wrapper;
import com.deppon.dop.module.sdk.shared.domain.result.ResultDO;
import com.deppon.dop.module.sdk.shared.util.HttpUtils;
import com.deppon.dop.module.sdk.shared.util.SecurityUtil;
import com.ztgf.common.constant.Result;
import com.ztgf.common.enums.CodeEnum;
import com.ztgf.dubbo.exception.ServiceException;
import com.ztgf.common.utils.DateUtils;
import com.ztgf.common.utils.StrUtils;
import com.ztgf.common.vo.UserVO;
import com.ztgf.db.utils.RedisUtil;
import com.ztgf.logistics.common.config.YmlConfig;
import com.ztgf.logistics.models.bo.deppon.LogisticsHttpLogSaveBO;
import com.ztgf.logistics.models.bo.deppon.LogisticsOrderEditBO;
import com.ztgf.logistics.models.bo.deppon.LogisticsOrderSaveBO;
import com.ztgf.logistics.models.bo.deppon.api.*;
import com.ztgf.logistics.models.dto.deppon.LogisticsOrderDTO;
import com.ztgf.logistics.models.dto.deppon.LogisticsOrderRemarkDTO;
import com.ztgf.logistics.models.service.deppon.ILogisticsDepponOrderService;
import com.ztgf.logistics.models.service.deppon.ILogisticsHttpLogService;
import com.ztgf.logistics.models.service.deppon.ILogisticsOrderService;
import com.ztgf.logistics.models.vo.deppon.api.*;
import com.ztgf.logistics.service.api.IDepponService;
import com.ztgf.shopping.models.dto.shop.ShopInfoDTO;
import com.ztgf.shopping.models.service.shop.IShopInfoService;
import com.ztgf.sys.models.service.ISessionService;
import io.swagger.annotations.ApiModelProperty;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.httpclient.NameValuePair;
import org.apache.dubbo.config.annotation.DubboReference;
import org.apache.dubbo.config.annotation.DubboService;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;

import javax.annotation.Resource;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.PrintWriter;

/**
 * @Description:
 * @Author: mxli
 * @Date: 2021-10-19 10:24
 **/
@DubboService
@Slf4j
public class LogisticsDepponOrderServiceImpl implements ILogisticsDepponOrderService {

    @Resource
    private ILogisticsOrderService logisticsOrderService;
    @Resource
    private IDepponService depponService;
    @Resource
    private ISessionService sessionService;
    @Resource
    private YmlConfig ymlConfig;
    @DubboReference
    private IShopInfoService shopInfoService;
    @Resource
    private ILogisticsHttpLogService logisticsHttpLogService;
    @Value("${deppon-api.customer-code}")
    private String customerCode;
    @Value("${deppon-api.sign}")
    private String sign;
    @Value("${deppon-api.company-code}")
    private String companyCode;
    @Value("${deppon-api.app-key}")
    private String appKey;

    @Override
    public Result add(LogisticsOrderSaveBO saveBO) {
//        if(){
//
//        }
        Long shopId = 0L;
        String shopName = "";
        Integer userType = 0;
        UserVO userVO = sessionService.getUserVO();
        if(userVO.getType() == 0){//普通用户
            ShopInfoDTO shopInfoDTO = shopInfoService.getByUserId(userVO.getId());
            shopId = shopInfoDTO.getId();
            shopName = shopInfoDTO.getName();
        } else {
            userType = 1;
        }
        Long id = ymlConfig.getPkId();
        saveBO.setShopId(shopId);
        saveBO.setShopName(shopName);
        saveBO.setUserType(userType);
        saveBO.setCreateUserId(userVO.getId());
        saveBO.setCreateUserName(userVO.getName());
        saveBO.setOrderType("1");//1、 散客模式（单量较小，平台类，异地调货，退换货等发货地址不固定-需要通知快递员或者司机上门取件打单;整车订单也选此模式）； 2、 大客户模式（仓库发货，固定点出货，单量较大客户自行打印标签，快递员直接盲扫走货）3、同步筛单下单（只支持大客户模式快递下单）
        //运输方式/产品类型", required = true)
        if(StrUtils.isEmpty(saveBO.getTransportType())){
            saveBO.setTransportType("PACKAGE");//（具体传值请与月结合同签订约定的为准，否则可能影响计费） 快递运输方式 : RCP：大件快递360； NZBRH：重包入户； ZBTH：重包特惠； WXJTH：微小件特惠； JJDJ：经济大件； PACKAGE：标准快递；HKDJC：航空大件次日达; HKDJG：航空大件隔日达; TZKJC：特快专递; 零担运输方式： JZKY：精准空运（仅散客模式支持该运输方式）; JZQY_LONG：精准汽运； JZKH：精准卡航； 整车运输方式 1.整车配送 ZCPS 2.精准专车 JZZHC
        }
        //第三方接入商的公司编码 渠道来源", required = true)
        saveBO.setCompanyCode(companyCode);
        //客户编码/月结账号", required = true)
        saveBO.setCustomerCode(customerCode);//德邦一线营业部给到客户的月结客户编码，由营业部给出。沙箱环境，下子母件订单必须传值 219401 或者219402


        String logisticId = sign + id;
        saveBO.setId(id);
        saveBO.setLogisticId(logisticId);
        try{
            logisticsOrderService.add(saveBO);
        } catch (ServiceException e){
            log.error("发货失败ServiceException：", e);
            return new Result(e.getCode(), e.getMessage());
        } catch (RuntimeException e){
            log.error("发货失败RuntimeException：", e);
            return new Result(CodeEnum.FAIL_DEPPON_400002);
        } catch (Exception e){
            log.error("发货失败RuntimeException：", e);
            return new Result(CodeEnum.FAIL_DEPPON_400002);
        }

        DepponAddOrderBO orderBO = new DepponAddOrderBO();

        //渠道单号", required = true)
        orderBO.setLogisticID(logisticId);
        //客户的订单号")
        orderBO.setCustOrderNo(saveBO.getCustOrderNo());

        //是否需要订阅轨迹：1：是（为是时要对接轨迹推送接口） 2：否 默认否")
        orderBO.setNeedTraceInfo(saveBO.getNeedTraceInfo());

        //第三方接入商的公司编码 渠道来源", required = true)
        orderBO.setCompanyCode(saveBO.getCompanyCode());
        //下单模式", required = true)
        orderBO.setOrderType(saveBO.getOrderType());//1、 散客模式（单量较小，平台类，异地调货，退换货等发货地址不固定-需要通知快递员或者司机上门取件打单;整车订单也选此模式）； 2、 大客户模式（仓库发货，固定点出货，单量较大客户自行打印标签，快递员直接盲扫走货）3、同步筛单下单（只支持大客户模式快递下单）

        //运输方式/产品类型", required = true)
        orderBO.setTransportType(saveBO.getTransportType());//（具体传值请与月结合同签订约定的为准，否则可能影响计费） 快递运输方式 : RCP：大件快递360； NZBRH：重包入户； ZBTH：重包特惠； WXJTH：微小件特惠； JJDJ：经济大件； PACKAGE：标准快递；HKDJC：航空大件次日达; HKDJG：航空大件隔日达; TZKJC：特快专递; 零担运输方式： JZKY：精准空运（仅散客模式支持该运输方式）; JZQY_LONG：精准汽运； JZKH：精准卡航； 整车运输方式 1.整车配送 ZCPS 2.精准专车 JZZHC

        //客户编码/月结账号", required = true)
        orderBO.setCustomerCode(saveBO.getCustomerCode());//德邦一线营业部给到客户的月结客户编码，由营业部给出。沙箱环境，下子母件订单必须传值 219401 或者219402

        //发货人信息", required = true)
        DepponContactsBO sender = new DepponContactsBO();
        //发货人公司")
        sender.setCompanyName(saveBO.getSenderCompanyName());
        //发货部门编码")
        sender.setBusinessNetworkNo(saveBO.getSenderBusinessNetworkNo());
        sender.setName(saveBO.getSenderName());
        //发货人手机", required = true)
        sender.setMobile(saveBO.getSenderMobile());
        //发货人电话")
        sender.setPhone(saveBO.getSenderPhone());
        //发货人省份", required = true)
        sender.setProvince(saveBO.getSenderProvince());
        //发货人城市", required = true)
        sender.setCity(saveBO.getSenderCity());
        //发货人区县", required = true)
        sender.setCounty(saveBO.getSenderCounty());
        //发货人乡镇街道")
        sender.setTown(saveBO.getSenderTown());
        //发货人详细地址", required = true)
        sender.setAddress(saveBO.getSenderAddress());

        orderBO.setSender(sender);
        //收货人信息", required = true)
        DepponContactsBO receiver = new DepponContactsBO();
        //收货人公司")
        receiver.setCompanyName(saveBO.getReceiverCompanyName());
        receiver.setName(saveBO.getReceiverName());
        //收货人手机", required = true)
        receiver.setMobile(saveBO.getReceiverMobile());
        //收货人电话")
        receiver.setPhone(saveBO.getReceiverPhone());
        //收货人省份", required = true)
        receiver.setProvince(saveBO.getReceiverProvince());
        //收货人城市", required = true)
        receiver.setCity(saveBO.getReceiverCity());
        //收货人区县", required = true)
        receiver.setCounty(saveBO.getReceiverCounty());
        //收货人乡镇街道")
        receiver.setTown(saveBO.getReceiverTown());
        //收货人详细地址", required = true)
        receiver.setAddress(saveBO.getReceiverAddress());
        //到达部门编码：德邦营业部门编码，若没有同步德邦营业部门数据，可以不填")
        receiver.setToNetworkNo(saveBO.getReceiverToNetworkNo());
        orderBO.setReceiver(receiver);
        //包裹信息", required = true)
        DepponPackageInfoBO packageInfo = new DepponPackageInfoBO();
        //货物名称", required = true)
        packageInfo.setCargoName(saveBO.getCargoName());
        //总件数（包裹数）", required = true)
        packageInfo.setTotalNumber(saveBO.getTotalNumber());
        //总重量单位：kg", required = true)
        packageInfo.setTotalWeight(saveBO.getTotalWeight());
        //总体积单位：m3")
        packageInfo.setTotalVolume(saveBO.getTotalVolume());
        //包装（直接用中文） ： 纸、纤、木箱、木架、托膜、托木（大客户模式下运输方式为零担时必填）")
        packageInfo.setPackageService(saveBO.getPackageService());
        //送货方式: 1、自提； 2、送货进仓； 3、送货（不含上楼）； 4、送货上楼； 5、大件上楼", required = true)
        packageInfo.setDeliveryType(saveBO.getDeliveryType());
        orderBO.setPackageInfo(packageInfo);

        //订单提交时间", required = true)
        orderBO.setGmtCommit(DateUtils.getCurrentDateTimeStr());//系统当前时间,格式为 yyyy-MM-dd HH:mm:ss 如 2020-11-07 18:44:19
        //支付方式", required = true)
        orderBO.setPayType(saveBO.getPayType());//：0、发货人付款（现付）（大客户模式不支持寄付） 1、收货人付款（到付） 2、发货人付款（月结）


        //增值服务")
        DepponAddServicesBO addServices = new DepponAddServicesBO();
        //保价金额：单位：元")
        addServices.setInsuranceValue(saveBO.getInsuranceValue());
        //代收货款类型：0：无代收 1：即日退 3：三日退 代收货款金额不为0时，此项客户必填，代收货款金额为0或为空，则代收类型默认为无")
        addServices.setCodType(saveBO.getCodType());

        //代收货款客户账号：代收货款金额不为0时，此项客户必填")
        addServices.setReciveLoanAccount(saveBO.getReciveLoanAccount());
        //代收货款客户开户名：代收货款金额不为0时，此项客户必填")
        addServices.setAccountName(saveBO.getAccountName());
        //代收货款金额：可为空 如为空，则FOSS开单时默认为0，单位：元")
        addServices.setCodValue(saveBO.getCodValue());
        //签收回单：", required = true)
        addServices.setBackSignBill(saveBO.getBackSignBill());//0:无需返单 1：签收单原件返回 2:电子签收单（电子签名图片需要另外对接查询接口）
        orderBO.setAddServices(addServices);

        //短信通知：Y：需要 N: 不需要")
        orderBO.setSmsNotify(saveBO.getSmsNotify());
        //上门接货开始时间")
        orderBO.setSendStartTime(saveBO.getSendStartTime());//方便上门接货的时间范围(yyyy-MM-dd HH:mm:ss)
        //上门接货结束时间")
        orderBO.setSendEndTime(saveBO.getSendEndTime());


        //原运单号：异地调货退货场景可能用到")
        orderBO.setOriginalWaybillNumber(saveBO.getOriginalWaybillNumber());

        //备注")
        orderBO.setRemark(saveBO.getRemark());


        //是否外发：Y：需要 N: 不需要（仅适用于下单模式为2且是零担运输方式；或者下单模式为3时）")
        orderBO.setIsOut(saveBO.getIsOut());
        //是否口令签收：仅适用于快递，Y：需要 N: 不需要；若为Y，必须收货人提供验证码给快递员才能签收，该服务是有偿的，具体费用请让我司收货营业部联系张宁（491407），请慎重使用！")
        orderBO.setPasswordSigning(saveBO.getPasswordSigning());
        //是否可派送：Y：是 N:否")
        orderBO.setIsdispatched(saveBO.getIsdispatched());
        //是否预售单：Y：是N: 否")
        orderBO.setIspresaleorder(saveBO.getIspresaleorder());
        //是否合伙人自提：Y：是N: 否（只适用于同步筛单下单模式）")
        orderBO.setIsPickupSelf(saveBO.getIsPickupSelf());
        //是否接受仅镇中心派送：Y：是 N:否,若空时，默认为Y（只适用于同步筛单下单模式）")
        orderBO.setIsCenterDelivery(saveBO.getIsCenterDelivery());
        DepponAddOrderVO vo = depponService.addOrder(orderBO);
        if(vo == null){
            return new Result(CodeEnum.FAIL_DEPPON_400001);
        }
        if(!vo.isResult()){
            //修改订单失败状态
            logisticsOrderService.saveCancel(id, vo.getReason());
            return new Result(CodeEnum.FAIL.getCode(), vo.getReason());
        }

        logisticsOrderService.updateMailNo(logisticId, vo.getMailNo(), CodeEnum.FAIL_DEPPON_400002);
        return new Result();
    }

    @Override
    public void saveDoNotify(HttpServletRequest request, HttpServletResponse response) {
        //时间戳
        String timestamp = request.getParameter("timestamp");
        //摘要
        String digest = request.getParameter("digest");
        //参数
        String params= request.getParameter("params");
        //时间戳验证使用，判断请求是否在有效的时间戳范围内，时间戳范围根据情况自行定义
        long sendTime=Long.parseLong(timestamp);
        long now = System.currentTimeMillis();
        long effectiveTimestamp=1800000;
        //摘要验证使用 appkey为双方约定
        String appkey="this is appkey";
        String expectDigest= SecurityUtil.getAlibabaDigest(params+appkey+timestamp);
        DepponResultVO resultVO = new DepponResultVO();
        resultVO.setResultCode("1000");
        resultVO.setResult(true);
        resultVO.setReason("成功");
        if(Math.abs(now - sendTime)>effectiveTimestamp){//时间戳验证
            resultVO.setResultCode("1001");
            resultVO.setResult(false);
            resultVO.setReason("时间戳失败");
        }else if (!expectDigest.equals(digest.trim())) {//摘要验证
            resultVO.setResultCode("1002");
            resultVO.setResult(false);
            resultVO.setReason("摘要验证失败");
        }
        DepponPushOrderBO bo = JSON.parseObject(params, DepponPushOrderBO.class);
        //TODO 处理业务逻辑
        //添加日志
        try {
            logisticsOrderService.saveDoNotify(bo);
        } catch (Exception e) {
            // 4 处理响应报文参数
            e.printStackTrace();
            log.error("回调错误", e);
            resultVO.setResultCode("1003");
            resultVO.setResult(false);
            resultVO.setReason("业务处理失败");
        } finally {
            // 5 响应智融平台
            PrintWriter out = null;
            try {
                String result = JSON.toJSONString(resultVO);

                out = response.getWriter();
                out.print(result);
                out.flush();

                LogisticsHttpLogSaveBO saveBO = new LogisticsHttpLogSaveBO();
                saveBO.setBusinessNotes("德邦物流回调");
                saveBO.setParams(params);
                saveBO.setReturnValue(result);
                int status = 1;
                if(resultVO.isResult()){
                    status = 0;
                }
                saveBO.setStatus(status);
                //添加日志
                logisticsHttpLogService.add(saveBO);
            } catch (Exception e) {
                e.printStackTrace();
            } finally {
                if (null != out) {
                    out.close();
                }
            }
        }
    }

    @Override
    public String getAlibabaDigest(String params, String timestamp) {
        return SecurityUtil.getAlibabaDigest(params + appKey + timestamp);
    }

}
